package cn.s1995.sloth.bizs.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.s1995.sloth.bizs.constant.BizCst;
import cn.s1995.sloth.bizs.constant.CacheNames;
import cn.s1995.sloth.bizs.entity.Prod;
import cn.s1995.sloth.bizs.entity.ProdGroupReference;
import cn.s1995.sloth.bizs.entity.Sku;
import cn.s1995.sloth.bizs.entity.UserCollection;
import cn.s1995.sloth.bizs.exception.BizException;
import cn.s1995.sloth.bizs.mapper.ProdMapper;
import cn.s1995.sloth.bizs.oo.req.ProdREQ;
import cn.s1995.sloth.bizs.oo.req.ProdSearchREQ;
import cn.s1995.sloth.bizs.oo.vo.ProdDetailVO;
import cn.s1995.sloth.bizs.oo.vo.ProdListVO;
import cn.s1995.sloth.bizs.service.*;
import cn.s1995.sloth.common.core.constant.enums.hint.Hint;
import cn.s1995.sloth.common.core.util.R;
import cn.s1995.sloth.common.security.util.SecurityUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 产品
 *
 * @author Lex
 * @date 2023-12-14 10:02:00
 */
@Slf4j
@Service
public class ProdServiceImpl extends ServiceImpl<ProdMapper, Prod> implements ProdService {

    @Resource
    private ProdCategoryService prodCategoryService;
    @Resource
    private SkuService skuService;
    // @Resource
    // private RemoteFileService remoteFileService;
    @Resource
    private ProdGroupReferenceService prodGroupReferenceService;
    @Resource
    private UserCollectionService userCollectionService;
    @Resource
    private ShopService shopService;
    @Resource
    private ProdEvaluateService prodEvaluateService;

    @Override
    @Cacheable(cacheNames = CacheNames.product, key = "#id")
    public Prod getProduct(Long id) {
        return this.getById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveProd(ProdREQ req) {
        checkParam(req);

        // 设置分类path
        req.setCategoryPath(prodCategoryService.buildCategoryPath(req.getCategoryId()));

        this.save(req);

        // 保存sku
        if (CollUtil.isNotEmpty(req.getSkuList())) {
            req.getSkuList().forEach(sku -> {
                sku.setProdId(req.getId());
                sku.setProdName(req.getName());
                if (StrUtil.isEmpty(sku.getPic())) {
                    sku.setPic(req.getPic());
                }
            });

            skuService.saveBatch(req.getSkuList());
        }

        // 保存分组
        if (CollUtil.isNotEmpty(req.getGroupList())) {
            List<ProdGroupReference> prodGroupReferenceList = req.getGroupList().stream().map(
                    item -> ProdGroupReference.builder()
                            .prodId(req.getId())
                            .shopId(req.getShopId())
                            .groupId(item)
                            .build()
            ).toList();
            prodGroupReferenceService.saveBatch(prodGroupReferenceList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheNames.product, key = "#req.id"),
            @CacheEvict(cacheNames = CacheNames.skuList, key = "#req.id")
    })
    public void updateProd(ProdREQ req) {
        checkParam(req);

        // 设置分类path
        req.setCategoryPath(prodCategoryService.buildCategoryPath(req.getCategoryId()));

        this.updateById(req);

        // 更新sku
        if (CollUtil.isNotEmpty(req.getSkuList())) {
            // 产品下的sku标记为删除
            skuService.update(
                    Wrappers.lambdaUpdate(Sku.class)
                            .set(Sku::getIsDeleted, Boolean.TRUE)
                            .eq(Sku::getProdId, req.getId())
            );

            req.getSkuList().forEach(sku -> {
                sku.setProdId(req.getId());
                // 设置删除状态为false
                sku.setIsDeleted(Boolean.FALSE);
                if (StrUtil.isNotEmpty(req.getName())) {
                    sku.setProdName(req.getName());
                }
                if (StrUtil.isEmpty(sku.getPic())) {
                    sku.setPic(req.getPic());
                }
            });
            skuService.saveOrUpdateBatch(req.getSkuList());
        }
        // 更新分组
        if (CollUtil.isNotEmpty(req.getGroupList())) {
            // 删除产品下的分组
            prodGroupReferenceService.remove(
                    Wrappers.lambdaQuery(ProdGroupReference.class)
                            .eq(ProdGroupReference::getProdId, req.getId())
            );
            // 保存产品下的分组
            List<ProdGroupReference> prodGroupReferenceList = req.getGroupList().stream().map(
                    item -> ProdGroupReference.builder()
                            .prodId(req.getId())
                            .shopId(req.getShopId())
                            .groupId(item)
                            .build()
            ).toList();
            prodGroupReferenceService.saveBatch(prodGroupReferenceList);
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheNames.product, key = "#prodId"),
            @CacheEvict(cacheNames = CacheNames.skuList, key = "#prodId")
    })
    public void removeProd(Long prodId) {

        removeById(prodId);

        // 删除sku
        skuService.remove(
                Wrappers.lambdaQuery(Sku.class)
                        .eq(Sku::getProdId, prodId)
        );
        // 删除分组产品关联
        prodGroupReferenceService.remove(
                Wrappers.lambdaQuery(ProdGroupReference.class)
                        .eq(ProdGroupReference::getProdId, prodId)
        );

        // Prod prod = getProduct(prodId);
        // // 删除产品相关图片
        // removeProdAssociationPic(prod);

    }

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheNames.product, key = "#prodId"),
            @CacheEvict(cacheNames = CacheNames.skuList, key = "#prodId")
    })
    public void removeProductCacheByProdId(Long prodId) {

    }

    /**
     * 检查参数
     *
     * @param req
     */
    private void checkParam(ProdREQ req) {
        // if (CollectionUtil.isEmpty(req.getGroupList())) {
        //     throw new BizException(Hint.BMS_PROD_CATEGORY_UNSELECTED);
        // }

        // if (CollectionUtil.isEmpty(req.getGroupList())) {
        //     throw new BizException(Hint.BMS_PROD_GROUP_UNSELECTED);
        // }

        // Product.DeliveryModeVO deliveryMode = req.getDeliveryModeVo();
        // boolean hasDeliverMode = deliveryMode != null
        //         && (deliveryMode.getHasShopDelivery() || deliveryMode.getHasUserPickUp());
        // if (!hasDeliverMode) {
        //     throw new YamiShopBindException(Hint.BMS_PROD_DELIVERY_TYPE_UNSELECTED);
        // }

        // 存在重复的产品
        long prodCount = this.count(
                Wrappers.lambdaQuery(Prod.class)
                        .eq(Prod::getShopId, req.getShopId())
                        .eq(Prod::getName, req.getName())
                        .ne(Objects.nonNull(req.getId()), Prod::getId, req.getId())
        );
        if (prodCount > 0) {
            throw new BizException(Hint.BMS_PROD_ALREADY_EXISTS);
        }

        List<Sku> skuList = req.getSkuList();
        boolean isAllUnUse = true;
        for (Sku sku : skuList) {
            if (Objects.nonNull(sku.getIsSale()) && sku.getIsSale()) {
                isAllUnUse = false;
            }
        }
        if (isAllUnUse) {
            throw new BizException(Hint.BMS_PROD_SKU_MUST_ENABLE_ONE);
        }
    }

    /**
     * 删除产品相关图片
     *
     * @param prod
     */
    private void removeProdAssociationPic(Prod prod) {
        // if (CollUtil.isNotEmpty(prod.getBanner())) {
        //     remoteFileService.removeByFileName(SecurityConstants.FROM_IN, prod.getBanner());
        // }
        // if (CollUtil.isNotEmpty(prod.getThumbnail())) {
        //     remoteFileService.removeByFileName(SecurityConstants.FROM_IN, prod.getThumbnail());
        // }
        // if (CollUtil.isNotEmpty(prod.getDescPic())) {
        //     remoteFileService.removeByFileName(SecurityConstants.FROM_IN, prod.getDescPic());
        // }
    }

	@Override
	public List<ProdListVO> setCollectStatus(Long uid, List<Prod> records) {
		Set<Long> set = userCollectionService.getUserCollectProdIds(uid);
		ArrayList<ProdListVO> res = new ArrayList<ProdListVO>();
		for (Prod prod : records) {
			ProdListVO vo = new ProdListVO();
			BeanUtil.copyProperties(prod, vo);
			if(set.contains(prod.getId()))
				vo.setCollectFlag(true);
			res.add(vo);
		}
		return res;
	}

	@Override
	public R collect(Long id) {
		Prod prod = this.getById(id);
		if(ObjectUtil.isNull(prod))
			return R.failed(Hint.NOT_FOUND);
		//判断是否已收藏过该产品
		Long uid = SecurityUtils.getUser().getId();
		Set<Long> userCollectProdIds = userCollectionService.getUserCollectProdIds(uid);
		if(userCollectProdIds.contains(id)) {
			//已收藏，取消收藏，修改数量
			userCollectionService.remove(
						Wrappers.lambdaQuery(UserCollection.class)
								.eq(UserCollection::getType, BizCst.UserCollection.Type.prod)
								.eq(UserCollection::getBindId, id)
								.eq(UserCollection::getUid, uid)
					);
			//数量统计只修改缓存
			//更新收藏集合缓存
			userCollectProdIds.remove(id);
			userCollectionService.updateUserCollectProdIds(uid, userCollectProdIds);
		}else {
			//收藏
			userCollectionService.save(
					UserCollection.builder()
								.type(BizCst.UserCollection.Type.prod)
								.uid(uid)
								.bindId(id)
								.build()
					);
			userCollectProdIds.add(id);
			userCollectionService.updateUserCollectProdIds(uid, userCollectProdIds);
		}
		return R.ok();
	}

	@Override
	public Page selectProdPage(Page page, ProdSearchREQ req) {
		return baseMapper.selectProdPage(page, req);
	}

    @Override
    public Prod getDeletedProd(Long id) {
        return baseMapper.getDeletedProd(id);
    }

    @Override
    public ProdDetailVO convertToDetailVO(Prod prod, Long uid) {
        if (ObjectUtil.isNull(prod)) {
            throw new BizException(Hint.APP_PROD_NOT_SALE, "");
        }
        ProdDetailVO vo = BeanUtil.copyProperties(prod, ProdDetailVO.class);
        // 设置sku
        vo.setSkuList(
                skuService.list(
                        Wrappers.lambdaQuery(Sku.class)
                                .eq(Sku::getProdId, vo.getId())
                                .eq(Sku::getIsSale, BizCst.CommonBool.yes)
                                .eq(Sku::getIsDeleted, BizCst.CommonBool.no)
                                .orderByAsc(Sku::getSort)
                )
        );
        // sku图片为空则设置为产品的图片
        if (ObjectUtil.isNotEmpty(vo.getSkuList())) {
            vo.getSkuList().forEach(
                    (sku) -> {
                        if (StrUtil.isBlank(sku.getPic())) {
                            sku.setPic(vo.getPic());
                        }
                    }
            );
        }
        // 产品评价
        vo.setEvaluation(prodEvaluateService.getProdData(prod.getId()));
        vo.setShop(shopService.getById(vo.getShopId()));
        // 回显收藏状态
        if (ObjectUtil.isNotNull(uid)) {
            Set<Long> set = userCollectionService.getUserCollectProdIds(uid);
            if (set.contains(prod.getId()))
                vo.setCollectFlag(true);
        }
        return vo;
    }

    @Override
    public Page<ProdListVO> getPage(Page page, ProdSearchREQ req, Long uid) {
        Page resPage = baseMapper.getPage(page, req);
        // 页面隐藏了收藏状态，暂不处理该逻辑
        // 回显用户收藏状态
        // List<ProdListVO> resultList = this.setCollectStatus(uid, resPage.getRecords());
        // resPage.setRecords(resultList);

        return resPage;
    }

    @Override
    public List<ProdListVO> getList(ProdSearchREQ req, Long uid) {
        List list = baseMapper.getList(req);
        // 页面隐藏了收藏状态，暂不处理该逻辑
        // 回显用户收藏状态
        // List<ProdListVO> resultList = this.setCollectStatus(uid, list);
        // return resultList;

        return list;
    }
}
